package com.zhhtech.zhh.ui.helper

import com.alibaba.fastjson.JSONObject

object PropertyPlaceholderHelper {
    private const val placeholderPrefix: String = "\${"
    private const val placeholderSuffix: String = "}"
    private const val simplePrefix: String = "{"
    private const val valueSeparator: String = ":"

//    @JvmStatic
//    fun parseStringValue(value: String, placeholderResolver: Any): String {
//        val json = (JSON.toJSON(placeholderResolver) as? JSONObject)?.also { parseObjToMap(null, it, it) }
//        return parseStringValue(value, json)
//    }

    @JvmStatic
    fun parseObjToMap(parentKey: String?, rootJson: JSONObject, jsonObject: JSONObject) {
        val entries: Set<Map.Entry<String, Any>> = HashSet(jsonObject.entries)
        for (entry in entries) {
            var cKey = entry.key
            if (parentKey != null) {
                cKey = parentKey + "." + entry.key
            }
            if (entry.value is JSONObject) {
                parseObjToMap(cKey, rootJson, entry.value as JSONObject)
            } else if (rootJson !== jsonObject) {
                rootJson[cKey] = entry.value
            }
        }
    }

    @JvmStatic
    fun parseStringValue(value: String, placeholderResolver: JSONObject?): String {
        var startIndex = value.indexOf(placeholderPrefix)
        if (startIndex == -1) {
            return value
        }
        val result = StringBuilder(value)
        while (startIndex != -1) {
            val endIndex = findPlaceholderEndIndex(result, startIndex)
            if (endIndex != -1) {
                var placeholder = result.substring(startIndex + placeholderPrefix.length, endIndex)
                placeholder = parseStringValue(placeholder, placeholderResolver)
                var propVal: String? = placeholderResolver?.get(placeholder)?.toString()
                if (propVal == null) {
                    val separatorIndex = placeholder.indexOf(valueSeparator)
                    if (separatorIndex != -1) {
                        val actualPlaceholder = placeholder.substring(0, separatorIndex)
                        val defaultValue = placeholder.substring(separatorIndex + valueSeparator.length)
                        propVal = placeholderResolver?.get(actualPlaceholder)?.toString()
                        if (propVal == null) {
                            propVal = defaultValue
                        }
                    }
                }
                if (propVal != null) {
                    propVal = parseStringValue(propVal, placeholderResolver)
                    result.replace(startIndex, endIndex + placeholderSuffix.length, propVal)
                    startIndex = result.indexOf(placeholderPrefix, startIndex + propVal.length)
                } else {
                    startIndex = result.indexOf(placeholderPrefix, endIndex + placeholderSuffix.length)
                }
            } else {
                startIndex = -1
            }
        }
        return result.toString()
    }

    private fun findPlaceholderEndIndex(buf: CharSequence, startIndex: Int): Int {
        var index = startIndex + placeholderPrefix.length
        var withinNestedPlaceholder = 0
        while (index < buf.length) {
            if (substringMatch(buf, index, placeholderSuffix)) {
                index = if (withinNestedPlaceholder > 0) {
                    withinNestedPlaceholder--
                    index + placeholderSuffix.length
                } else {
                    return index
                }
            } else if (substringMatch(buf, index, simplePrefix)) {
                withinNestedPlaceholder++
                index += simplePrefix.length
            } else {
                index++
            }
        }
        return -1
    }

    private fun substringMatch(str: CharSequence, index: Int, substring: CharSequence): Boolean {
        if (index + substring.length > str.length) {
            return false
        }
        for (i in substring.indices) {
            if (str[index + i] != substring[i]) {
                return false
            }
        }
        return true
    }
}